/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.aop;

import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.core.dto.*;
import com.intelligent.ispc.core.entity.*;
import com.intelligent.ispc.core.repository.jpa.*;
import com.intelligent.ispc.core.service.LogService;
import com.intelligent.ispc.core.service.SecurityService;
import com.intelligent.ispc.utils.LogUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

/**
 * Created by Peter on 2016/3/30.
 */
@Aspect
public class ProjectLogAspect {
    private static Logger logger = LoggerFactory.getLogger(ProjectLogAspect.class);

    @Autowired
    private LogService logService;

    @Autowired
    private SecurityService securityService;

    @Autowired
    private ProjectDao projectDao;

    @Autowired
    private PSAttributeDao psAttributeDao;

    @Autowired
    private StatisticAnalysisParameterDao statisticAnalysisParameterDao;

    @Autowired
    private CPWarningRuleDao cpWarningRuleDao;

    @Autowired
    private ControlChartWarningRuleDao controlChartWarningRuleDao;


    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.saveProject(..))")
    public void saveProjectCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.updateProject(..))")
    public void updateProjectCall() {
    }


    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.addPSAttribute(..))")
    public void addProjectAttrCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.deletePSAttribute(..))")
    public void deleteProjectAttrCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.updatePSAttribute(..))")
    public void updateProjectAttrCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.updateStatisticAnalysisParameter(..))")
    public void updateStatisticAnalysisParameterCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.updateCPWarningRule(..))")
    public void updateCPWarningRuleCall() {
    }

    @Pointcut("execution(* com.intelligent.ispc.core.service.impl.ProjectServiceImpl.updateControlChartWarningRule(..))")
    public void updateControlChartWarningRuleCall() {
    }



    /**
     * For Public insert operation (after returning)
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "saveProjectCall()")
    public Object saveProjectService(ProceedingJoinPoint joinPoint) throws Throwable {

        //Get the logined user name.
        String userLoginName = securityService.getCurrentUserLoginName();

        if (userLoginName == null) {
            //None logined user
            return null;
        }

        //check the arguments
        if (joinPoint.getArgs() == null) {//None args
            return null;
        }

        Object result = null;
        LogDto logDto = new LogDto();

        try {
            ProjectConfigureParameDto dto = (ProjectConfigureParameDto) joinPoint.getArgs()[0];
            logDto.setCreateBy(userLoginName);
            logDto.setCreateTime(new Date());
            logDto.setOperation(LogUtil.INSERT.getCode());
            StringBuffer msg = new StringBuffer().append(getLogCell(ApplicationModule.MODULE_PROJECT));
            msg.append(getLogCell("New Project"));

            if (dto != null) {
                msg.append(getLogCell(",", "Code: " + dto.getCode(), "Name: " + dto.getName()));
                logDto.setContent(msg.toString());
                logDto.setResult(LogUtil.SUCCESS.getCode());
            }
            result = joinPoint.proceed();

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }


    /**
     * For Public insert operation (after returning)
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "updateProjectCall()")
    public Object updateProjectService(ProceedingJoinPoint joinPoint) throws Throwable {

        //Get the logined user name.
        String userLoginName = securityService.getCurrentUserLoginName();

        if (userLoginName == null) {
            //None logined user
            return null;
        }

        //check the arguments
        if (joinPoint.getArgs() == null) {//None args
            return null;
        }

        Object result = null;
        LogDto logDto = new LogDto();

        try {
            ProjectDto dto = (ProjectDto) joinPoint.getArgs()[0];

            Project entity = projectDao.findById(dto.getId());
            logDto.setCreateBy(userLoginName);
            logDto.setCreateTime(new Date());
            logDto.setOperation(LogUtil.UPDATE.getCode());
            StringBuffer msg = new StringBuffer().append(getLogCell(ApplicationModule.MODULE_PROJECT));
            msg.append(getLogCell("Update Project"));

            if (entity != null) {
                msg.append(getLogCell(", ", "Code: " + entity.getCode(), "Name: " + entity.getName()));
                logDto.setContent(msg.toString());
                logDto.setResult(LogUtil.SUCCESS.getCode());
            }

            result = joinPoint.proceed();

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }

    /**
     * For add PS Attribute.
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "addProjectAttrCall()")
    public Object addPSAttributeService(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        PSAttributeDto dto = (PSAttributeDto) args[0];
        ProjectDto projectDto = dto.getProject();

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("New Attribute"));
        String projectName = "";
        if (projectDto != null && projectDto.getId() != null) {
            Project project = projectDao.findById(projectDto.getId());
            if (project != null) {
                projectName = project.getName();
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.UPDATE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, "Attribute: " + dto.getName(), "Value: " + dto.getValue()));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }

    /**
     * For delete PS Attribute.
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "deleteProjectAttrCall()")
    public Object deletePSAttributeService(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        String id = (String) args[0];
        PSAttribute entity = psAttributeDao.findById(new Long(id));

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("Delete Attribute"));

        String projectName = "";
        if (entity != null && entity.getProject() != null) {
            Project project = projectDao.findById(entity.getProject().getId());
            if (project != null) {
                projectName = project.getName();
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.DELETE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, "Attribute: " + entity.getName()));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }

    /**
     * For update PS Attribute.
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "updateProjectAttrCall()")
    public Object updatePSAttributeService(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        PSAttributeDto dto = (PSAttributeDto) args[0];

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("Update Attribute"));
        String projectName = "";
        String psAttrName = "";
        if (dto != null && dto.getId() != null) {
            PSAttribute entity = psAttributeDao.findById(dto.getId());
            if (entity != null) {
                if (entity.getProject() != null) {
                    projectName = entity.getProject().getName();
                }
                psAttrName = entity.getName();
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.DELETE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, "Attribute: " + psAttrName, "Value: " + dto.getValue(), "Display: " + dto.getIsShow()));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }


    /**
     * For update PS Attribute.
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "updateStatisticAnalysisParameterCall()")
    public Object updateStatisticAnalysisParameterCall(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        StatisticAnalysisParameterDto dto = (StatisticAnalysisParameterDto) args[0];

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("Update Settings"));
        String projectName = "";
        String dcGroup = "default";
        String ccGroup = "default";

        if (dto != null && dto.getId() != null) {
            StatisticAnalysisParameter entity = statisticAnalysisParameterDao.findById(dto.getId());
            if (entity != null) {
                if (entity.getProject() != null) {
                    projectName = entity.getProject().getName();
                }
                if (dto.getDistributionChartGroupingNumber() != null) {
                    dcGroup = dto.getDistributionChartGroupingNumber().toString();
                }
                if (dto.getControlChartGroupingNumber() != null) {
                    ccGroup = dto.getControlChartGroupingNumber().toString();
                }
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.UPDATE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, "DCGroup: " + dcGroup, "CCGroup: " + ccGroup));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }


    /**
     * For update PS Attribute.
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around(value = "updateCPWarningRuleCall()")
    public Object updateCPWarningRuleService(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        CPWarningRuleDto dto = (CPWarningRuleDto) args[0];

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("Update CP Warning Rule"));
        String projectName = "";
        String content = "";

        if (dto != null && dto.getId() != null) {
            CPWarningRule entity = cpWarningRuleDao.findById(dto.getId());
            if (entity != null) {
                if (entity.getProject() != null) {
                    projectName = entity.getProject().getName();
                }
                if (entity.getIndiceName() != null) {
                    content += "Name: " + entity.getIndiceName() + ", ";
                }
                if (dto.getExcellentBoundaryValue() != null) {
                    content += "Excellence: " + dto.getExcellentBoundaryValue();
                }
                if (dto.getGoodBoundaryValue() != null) {
                    content += "Well: " + dto.getGoodBoundaryValue();
                }
                if (dto.getAcceptableBoundaryValue() != null) {
                    content += "Accept: " + dto.getAcceptableBoundaryValue();
                }
                if (dto.getRectificationBoundaryValue() != null) {
                    content += "Rectification: " + dto.getRectificationBoundaryValue();
                }
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.UPDATE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, content));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }

    @Around(value = "updateControlChartWarningRuleCall()")
    public Object updateControlChartWarningRuleService(ProceedingJoinPoint joinPoint) throws Throwable {
        String userLoginName = securityService.getCurrentUserLoginName();

        Object result = null;

        if (userLoginName == null || joinPoint.getArgs() == null) {
            return null;
        }

        Object[] args = joinPoint.getArgs();

        ControlChartWarningRuleDto dto = (ControlChartWarningRuleDto) args[0];

        StringBuffer msg = new StringBuffer();
        msg.append(getLogCell(ApplicationModule.MODULE_PROJECT));
        msg.append(getLogCell("Update CC Warning Rule"));
        String projectName = "";
        String content = "";

        if (dto != null && dto.getId() != null) {
            ControlChartWarningRule entity = controlChartWarningRuleDao.findById(dto.getId());
            if (entity != null) {
                if (entity.getProject() != null) {
                    projectName = entity.getProject().getName();
                }
                if (entity.getCode() != null) {
                    content += "Name: " + entity.getCode() + ", ";
                }
                if (dto.getPoints() != null) {
                    content += "param1: " + dto.getPoints();
                }
                if (dto.getSomePoints() != null) {
                    content += "param2: " + dto.getSomePoints();
                }
                if (dto.getSigma() != null) {
                    content += "Sigma: " + dto.getSigma();
                }
            }
        }

        LogDto logDto = new LogDto();
        logDto.setCreateBy(userLoginName);
        logDto.setCreateTime(new Date());
        logDto.setOperation(LogUtil.UPDATE.getCode());

        try {
            result = joinPoint.proceed();

            msg.append(getLogCell(", ", "Project: " + projectName, content));
            logDto.setContent(msg.toString());
            logDto.setResult(LogUtil.SUCCESS.getCode());

        } catch (Exception ex) {
            logDto.setResult(LogUtil.FAILURE.getCode());
            throw new ApplicationException(ex.getMessage());
        } finally {
            logService.log(logDto);
        }

        return result;
    }



    private String getLogCell(String content) {
        return "[" + content + "]";
    }

    private String getLogCell(String sp, String... contents) {
        StringBuffer msg = new StringBuffer();
        msg.append("[");
        if (sp != null) {
            for (String s : contents) {
                msg.append(s).append(sp);
            }
        }
        msg.deleteCharAt(msg.lastIndexOf(sp));
        msg.append("]");
        return msg.toString();
    }
}
